/*
 *   Copyright (C) 2009  Jens Kieselbach
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You may obtain a copy of the License at http://www.gnu.org/licenses/gpl.html
 */
package de.kieselbach.grootional

import de.kieselbach.grootional.component.*
import de.kieselbach.grootional.dialog.*
import de.kieselbach.grootional.util.*
import de.kieselbach.grootional.value.*
import de.kieselbach.swing.*
import groovy.xml.*
import java.awt.*
import java.util.logging.*
import javax.swing.*

class MainFrame {

    def uiResources
    def resourceBundle

    def frame
    def cardPane

    def doExit = {event ->
        exit()
    }

    def doAbout = {event ->
        new AboutDialog(this).show()
    }


    def doNewConnectionCard = {event ->
        addNewConnectionCard();
    }

    MainFrame(def uires) {

        frame = new JFrame()
        frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE
        frame.windowClosing = doExit

        uiResources = uires

        frame.iconImage = uiResources.images['grootional'].image
        resourceBundle = uiResources.resourceBundles['gui']

        frame.title = resourceBundle.getString('main.title')

        def uiset = uiResources.createUISet('main')
        uiset.actions['exit'] = doExit
        uiset.actions['about'] = doAbout
        uiset.actions['newconnectioncard'] = doNewConnectionCard

        frame.setJMenuBar(uiset.menuBar)

        def main = new JPanel(new BorderLayout(0, 0))
        frame.contentPane = main

        main.add(uiset.toolBar as JToolBar, BorderLayout.NORTH)

        cardPane = new CardPane(frame, uiResources)
        main.add(cardPane, BorderLayout.CENTER)
    }

    // -----------------------------------------------------------------------------------------------------------------------

    void addNewConnectionCard() {

        cardPane.addCard(new ConnectionListCard(this, resourceBundle.getString('main.connections') + ' ' + (cardPane.count+1)), true)
    }

    // -----------------------------------------------------------------------------------------------------------------------

    def databaseFrameDescriptions = [] as Set
    def databaseFrames = [] as LinkedHashSet
    def databaseFrameProperties = [:]
    def confirmClosing = false

    void openDatabaseFrame(def conval) {

        def desc = conval.description
        def num = 2
        while(databaseFrameDescriptions.contains(desc)) {
            desc = conval.description + ' (' + num + ')'
            num++
        }
        databaseFrameDescriptions << desc

        def cl = {f ->
            databaseFrameDescriptions.remove(f.description)
            databaseFrames.remove(f)

            def props = [:]
            f.properties.each() {key,value ->
                props[key] = value
            }
            databaseFrameProperties[f.id] = props
        }

        def dbframe = new DatabaseFrame(uiResources, cl, new DatabaseConnectionPool(desc, new ConnectionValue(conval)))
        databaseFrames << dbframe
        dbframe.show(databaseFrameProperties[conval.id])
    }

    // -----------------------------------------------------------------------------------------------------------------------

    final def SETTINGS_FILE = '.grootional'

    void show() {

        def x = 0
        def y = 0
        def w = 300
        def h = 600

        def toInt = {str, defval ->
            if (str != null && str.isInteger()) {
                return Integer.parseInt(str)
            }
            else {
                return defval
            }
        }

        def toLong = {str ->
            if (str != null && str.isLong()) {
                return Long.parseLong(str )
            }
            else {
                return 0
            }
        }

        try {
            def file = new File((System.properties.'user.home' + System.properties.'file.separator' + SETTINGS_FILE) as String)
            if(file.exists()) {
                file.withInputStream {input ->
                    def result = new XmlParser().parse(input)

                    if (result.'mainframe'.size() == 1) {
                        x = toInt(result.'mainframe'[0].'@x', x)
                        y = toInt(result.'mainframe'[0].'@y', y)
                        w = toInt(result.'mainframe'[0].'@width', w)
                        h = toInt(result.'mainframe'[0].'@height', h)
                    }
                    else if (result.'mainframe'.size() > 1) {
                        throw new IOException('the settings file is invalid!')
                    }

                    if (result.'databaseframes'.size() == 1) {
                        result.'databaseframes'.'databaseframe'.each() {elem ->
                            def id = toLong(elem.'@connectionid')
                            if(id > 0) {
                                def props = [:]
                                databaseFrameProperties[id] = props
                                elem.'property'.each() {prop ->
                                    def key = prop.'@key'
                                    def val = prop.'@value'
                                    if(key != null && val != null) {
                                        props[key] = val
                                    }
                                }
                            }
                        }
                    }
                    else if (result.'databaseframes'.size() > 1) {
                        throw new IOException('the settings file is invalid!')
                    }
                    
                    if (result.'cards'.size() == 1) {
                        def visible = toInt(result.'cards'[0].'@visible', 0)
                        def i = 0
                        result.'cards'.'card'.each() {elem ->
                            cardPane.addCard(MainFrameCard.readFromXml(elem, this), i == visible)
                            i++
                        }
                    }
                    else if (result.'cards'.size() > 1) {
                        throw new IOException('the settings file is invalid!')
                    }

                    
                }
            }
        }
        catch (Exception exc) {
            Logger.getLogger(getClass().name).log(Level.SEVERE, 'Unable to load settings!', exc)
        }

        if(cardPane.count <= 0) {
            addNewConnectionCard()
        }

        frame.size = [w, h]
        frame.location = [x, y]
        frame.visible = true
    }

    void exit() {

        if(databaseFrames.size() > 0) {

            def panebuilder = new PaneBuilder()
            if(confirmClosing && panebuilder.question(resourceBundle.getString('main.exittitle'), message: resourceBundle.getString('main.exitconfirmation'), owner: frame, options: ['yes', 'no'], default: 'yes') != 'yes') {
                return
            }

            new LinkedList(databaseFrames).reverseEach() {f ->
                f.close()
            }
        }

        frame.visible = false
        frame.dispose()

        try {
            def file = new File((System.properties.'user.home' + System.properties.'file.separator' + SETTINGS_FILE) as String)

            file.withPrintWriter 'UTF-8', {writer ->

                writer.println('<?xml version="1.0" encoding="UTF-8"?>')
                writer.println()

                def xml = new MarkupBuilder(writer as PrintWriter)
                xml.grootional() {

                    mainframe(x: frame.location.@x as String, y: frame.location.@y as String, width: frame.width as String, height: frame.height as String) {

                    }

                    databaseframes() {
                        cardPane.cards.each() {card ->
                            card.getConnectionIds().each() {id ->
                                def props = databaseFrameProperties[id]
                                if(props != null && props.size() > 0) {
                                    databaseframe(connectionid: id) {
                                        props.each() {k,v ->
                                            property(key: k, value: v)
                                        }
                                    }
                                }
                            }
                        }
                    }

                    cards(visible: cardPane.visibleCardIndex != null ? cardPane.visibleCardIndex as String : '') {
                        cardPane.cards.each() {card ->
                            card.writeToXml(xml)
                        }
                    }
                }
            }
        }
        catch (Exception exc) {
            Logger.getLogger(getClass().name).log(Level.SEVERE, 'Unable to save settings!', exc)
        }
        
        System.exit(0)
    }
}
